package ru.cannabis;

import ru.cannabis.command.base.AbstractCommand;
import ru.cannabis.command.base.CommandFactory;
import ru.cannabis.notification.ErrorSendableToUser;
import ru.cannabis.notification.JSONErrorResponse;
import org.apache.mina.core.service.IoHandlerAdapter;
import org.apache.mina.core.session.IoSession;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import java.util.Date;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;


public class MainHandler extends IoHandlerAdapter {

	private static Logger log = LoggerFactory.getLogger(MainHandler.class);

	@Autowired
	private CommandFactory commandFactory;

	public CommandFactory getCommandFactory()
    {
		return commandFactory;
	}

	public void setCommandFactory(CommandFactory commandFactory)
    {
		this.commandFactory = commandFactory;
	}

	private final BlockingQueue<AbstractCommand> queue = new LinkedBlockingQueue<AbstractCommand>();

	public void addCommand(AbstractCommand command)
    {
		try {
			if (command != null) {
				queue.put(command);
			}
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}

	@Override
	public void messageReceived(IoSession session, Object message)
    {
		AbstractCommand command = commandFactory.createFromJson(session, message.toString());
		addCommand(command);
	}

	public void execute()
    {
		ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
		executor.setCorePoolSize(2);
		executor.initialize();
		executor.execute(new Runnable() {

			@Override
			public void run()
            {
				AbstractCommand command;
				while (true)
                {
					while ((command = queue.poll()) == null)
                    {
						try
                        {
							Thread.sleep(50);
						}
                        catch (InterruptedException e)
                        {
							e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
						}
					}
					;

					/*if (ru.cannabis.command instanceof EndJailVoteCommand)
                    {
					}*/

					if (command.getSession() != null)
                    {
						System.out.println("Run: [" + command.getName() + "] for: " + command.getSession().getId() + "] params: " + command.getParams());
					}

					/*if (ru.cannabis.command instanceof CloseServerCommand)
                    {
						break;
					}*/

					try
                    {
						command.run();
					}
                    catch (Exception e)
                    {
						log.error(e.getMessage());
						e.printStackTrace();
					}

					if (command.getSession() != null)
                    {
						commandFactory.writeToSession(command.getSession(), command);
					}

					System.out.println(new Date());
					//System.out.println(ru.cannabis.Launcher.getRoomService().toString());
					//System.out.println(ru.cannabis.Launcher.getGameService().toString());
				}
			}
		});
	}

	public void exceptionCaught(IoSession session, Throwable cause)
    {
		cause.printStackTrace();

		if (cause instanceof ErrorSendableToUser)
        {
			JSONErrorResponse error = ((ErrorSendableToUser) cause).getError();
			commandFactory.writeToSession(session, error);
		}
		if (cause instanceof java.io.IOException)
        {
			session.close(true);
			return;
		}
		dumpState();
	}

	public void sessionClosed(IoSession session)
    {
		//AbstractCommand ru.cannabis.command = new SessionClosedCommand();
		//ru.cannabis.command.setSession(session);
		//addCommand(ru.cannabis.command);
	}

	private void dumpState()
    {
	}
}
